#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

import os
import sqlite3
import time
import uuid
from enum import Enum

from pydantic import BaseModel, Field

from common.common import convert_timestamp_to_time
from oracle import logger


class MetaDataSqliteService(object):
    @staticmethod
    def init_database(path):
        copy_metadata_sqlite_path = os.path.join(path, "sqlite")
        if not os.path.exists(copy_metadata_sqlite_path):
            logger.info("Start make copy metadata sqlite file ...")
            os.makedirs(copy_metadata_sqlite_path)
        sqlite_db_name = SqliteServiceField.SQLITE_DATABASE_NAME.value
        db_path = os.path.join(copy_metadata_sqlite_path, sqlite_db_name)
        if os.path.exists(db_path):
            os.remove(db_path)
        conn = sqlite3.connect(db_path)
        # 创建sqlite数据表T_COPY_METADATA存储副本下的数据库、数据表信息以及文件信息
        t_copy_metadata = SqliteServiceField.SQLITE_DATATABLE_NAME.value
        oracle_copy_metadata = SqliteServiceField.FILE_RESTORE_TABLE_NAME.value
        create_sql_table = MetaDataSqliteService.create_table_struct(t_copy_metadata)
        conn.execute(create_sql_table)
        conn.commit()
        create_file_restore_sql_table = MetaDataSqliteService.create_table_struct(oracle_copy_metadata)
        conn.execute(create_file_restore_sql_table)
        conn.commit()

    # 将表数据写入数据库
    @staticmethod
    def save_data(params, is_file_info=False):
        sqlite_db_name = SqliteServiceField.SQLITE_DATABASE_NAME.value
        db_path = os.path.join(params.get("path"), "sqlite", sqlite_db_name)
        conn = sqlite3.connect(db_path)
        if not is_file_info:
            # 创建sqlite数据表T_COPY_METADATA存储副本下的数据库、数据表信息
            table_name = SqliteServiceField.SQLITE_DATATABLE_NAME.value
        else:
            # 创建sqlite数据表ORACLE_COPY_METADATA存储副本下的单文件信息
            table_name = SqliteServiceField.FILE_RESTORE_TABLE_NAME.value
        # 数据库信息是否已经存在，用NAME+TYPE字段过滤，不存在则插入数据库结构信息
        statement = f'INSERT INTO {table_name} VALUES(?,?,?,?,?,?,?,?,?,?,?)'
        uuid1 = str(uuid.uuid1())
        obj_name = params.get("name")
        if obj_name is not None:
            database_data = MetaDataSqliteService.init_sql_params(params, uuid1)
            conn.executemany(statement, database_data)
            conn.commit()
        conn.close()
        return uuid1

    @staticmethod
    def save_data_batch(params_list, is_file_info=False):
        if params_list:
            sqlite_db_name = SqliteServiceField.SQLITE_DATABASE_NAME.value
            db_path = os.path.join(params_list[0].get("path"), "sqlite", sqlite_db_name)
            conn = sqlite3.connect(db_path)
            if not is_file_info:
                # 创建sqlite数据表T_COPY_METADATA存储副本下的数据库、数据表信息
                table_name = SqliteServiceField.SQLITE_DATATABLE_NAME.value
            else:
                # 创建sqlite数据表ORACLE_COPY_METADATA存储副本下的单文件信息
                table_name = SqliteServiceField.FILE_RESTORE_TABLE_NAME.value
            # 数据库信息是否已经存在，用NAME+TYPE字段过滤，不存在则插入数据库结构信息
            statement = f'INSERT INTO {table_name} VALUES(?,?,?,?,?,?,?,?,?,?,?)'
            for params in params_list:
                uuid1 = str(uuid.uuid1())
                obj_name = params.get("name")
                if obj_name is not None:
                    database_data = MetaDataSqliteService.init_sql_params(params, uuid1)
                    conn.executemany(statement, database_data)
            conn.commit()
            conn.close()

    @staticmethod
    def create_table_struct(table_name):
        return f'''create table IF NOT EXISTS '{table_name}'(
                UUID varchar(512) PRIMARY KEY NOT NULL, -- 唯一标识符，UUID格式
                NAME TEXT,  -- 数据库名、数据表明
                TYPE varchar(32), -- 类型：文件夹-d、文件-f
                PARENT_PATH TEXT,
                PARENT_UUID varchar(512),
                SIZE BIGINT,
                CREATE_TIME varchar(64), -- 创建时间
                MODIFY_TIME varchar(64), -- 修改时间时间
                EXTEND_INFO TEXT,
                RES_TYPE varchar (64),
                RES_SUB_TYPE varchar (64));'''

    @staticmethod
    def init_sql_params(params, uuid1):
        sqlite_table_params = SqliteTable()
        create_time = convert_timestamp_to_time(time.time())
        modify_time = convert_timestamp_to_time(time.time())
        obj_name = params.get("name")
        obj_type = params.get("type")
        parent_path = params.get("parent_path")
        extend_info = params.get("extend_info")
        parent_uuid = params.get("parent_uuid")
        size = params.get("size", sqlite_table_params.size)
        return [(uuid1, obj_name, obj_type, parent_path, parent_uuid,
                 size, create_time, modify_time, extend_info,
                 sqlite_table_params.res_type, sqlite_table_params.res_sub_type)]


class SqliteTable(BaseModel):
    uuid: str = Field(None, description='UUID')
    name: str = Field(None, description='name')
    type: str = Field(None, description='type')
    parent_path: str = Field(default='/', description='父节点路径')
    parent_uuid: str = Field(None, description='PARENT_UUID')
    size: str = Field(None, description='大小')
    create_time: str = Field(None, description='创建时间')
    modify_time: str = Field(None, description='修改时间')
    extend_info: str = Field(None, description='扩展信息')
    res_type: str = Field(None, description='RES_TYPE')
    res_sub_type: str = Field(None, description='RES_SUB_TYPE')


class SqliteServiceField(Enum):
    SQLITE_DATABASE_NAME = 'copymetadata.sqlite'
    SQLITE_DATATABLE_NAME = 'T_COPY_METADATA'
    FILE_RESTORE_TABLE_NAME = 'ORACLE_COPY_METADATA'
    TYPE_CLUSTER = 'cluster'
    TYPE_DATABASE = 'database'
    TYPE_TABLE = 'table'
